package com.me.myFramework.myAop.aop320;

import com.me.myFramework.myAop.aop320.advice.Advice;
import com.me.myFramework.myAop.aop320.advice.method.AfterReturningAdvice;
import com.me.myFramework.myAop.aop320.advice.method.MethodBeforeAdvice;
import com.me.myFramework.myAop.aop320.intercept.method.*;
import org.springframework.aop.Pointcut;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;

/**
 * 自己实现 AOP-3：  <p></p>
 *
 * 用来生成 AOP代理对象的工厂
 *
 * @author ME
 * @date 2021/9/27
 */
public class ProxyFactory {

    /** 目标对象 */
    private  Object target;
    /** 目标类 */
    private final Class<?> targetClass;

    /**
     * 一个完整的切面对象（pointcut + advice）
     */
    private final List<PointcutAdvisor> advisors = new ArrayList<>();

    public ProxyFactory(Object target) {
        this.target = target;
        this.targetClass = target.getClass();
    }

    /**
     * 动态代理织入增强逻辑，逻辑同 JdkDynamicAopProxy#getProxy(java.lang.ClassLoader)
     */
    public Object getProxy(ClassLoader classLoader) {
        Object proxy = null;

        List<MethodInterceptor> interceptors = getInterceptors(null, targetClass);
        for (int i = interceptors.size() - 1; i >= 0; i--) {
            proxy = Proxy.newProxyInstance(classLoader, targetClass.getInterfaces(), new ReflectiveMethodInvocation(this.target, interceptors.get(i)));
            this.target = proxy;
        }

        return proxy;
    }

    /**
     * 筛选出当前正在执行的方法适用的 advice（切面），并转换成 拦截器（执行增强逻辑的执行器）。
     * 逻辑类似 AdvisedSupport#getInterceptorsAndDynamicInterceptionAdvice(java.lang.reflect.Method, java.lang.Class)
     *
     * @param method        正在执行的方法
     * @param targetClass   目标类
     * @return  匹配当前方法的拦截器
     */
    private List<MethodInterceptor> getInterceptors(Method method, Class<?> targetClass) {
        List<MethodInterceptor> interceptorList = new ArrayList<>(this.advisors.size());
        for (PointcutAdvisor advisor : this.advisors) {
            Pointcut pointcut = advisor.getPointcut();
            if (pointcut.getClassFilter().matches(targetClass)) {
            // if (pointcut.getClassFilter().matches(targetClass) && pointcut.getMethodMatcher().matches(method, targetClass)) {
                Advice advice = advisor.getAdvice();
                if (advice instanceof MethodBeforeAdvice) {
                    // Spring 中是通过适配器（MethodBeforeAdviceAdapter）把 advice转换成拦截器的
                    interceptorList.add(new MethodBeforeAdviceInterceptor((MethodBeforeAdvice) advice));
                }
                else if (advice instanceof AfterReturningAdvice) {
                    interceptorList.add(new AfterReturningAdviceInterceptor((AfterReturningAdvice) advice));
                }
                else {
                    throw new RuntimeException("未知的 advice类型");
                }
            }
        }

        return interceptorList;
    }

    public void addAdvisor(PointcutAdvisor advisor) {
        this.advisors.add(advisor);
    }

}
